﻿using System;
using System.Collections.Generic;

namespace TekaMUD.Engine.Workers
{
	public class Supervisor
	{
		private object SyncRoot = new object();
		private static Supervisor _instance;
		public Dictionary<string, WorkerThread> RegisteredWorkers { get; set; }

		private static Supervisor Instance
		{
			get
			{
				return _instance;
			}
		}

		static Supervisor()
		{
			_instance = new Supervisor();
		}

		private Supervisor()
		{
			RegisteredWorkers = new Dictionary<string, WorkerThread>();
		}

		public static WorkerThread[] RegisteredThreads
		{
			get
			{
				lock (Instance.SyncRoot)
				{
					WorkerThread[] ret = new WorkerThread[Instance.RegisteredWorkers.Count];
					Instance.RegisteredWorkers.Values.CopyTo(ret, 0);

					return ret;
					
				}
			}
		}

		public static void AddWorker(WorkerThread wt)
		{
			lock (Instance.SyncRoot)
			{
				if (Instance.RegisteredWorkers.ContainsKey(wt.Name))
					throw new ArgumentException("Thread with duplicate name found");

				if (wt is ISingleWorker)
					foreach (WorkerThread w in Instance.RegisteredWorkers.Values)
						if (wt.GetType().Equals(w.GetType()))
							throw new ArgumentException("Worker already present");

				Instance.RegisteredWorkers.Add(wt.Name, wt);
				wt.ActivationDate = DateTime.Now;
			}
		}

		/// <summary>
		/// Starts all worker threads
		/// </summary>
		public static void StartAll()
		{
			lock (Instance.SyncRoot)
			{
				foreach (WorkerThread wt in Instance.RegisteredWorkers.Values)
					wt.Start();
			}
		}

		public static void SignalThreadsForTermination()
		{
			lock (Instance.SyncRoot)
			{
				foreach (WorkerThread wt in Instance.RegisteredWorkers.Values)
					wt.Terminate();
			}
		}

		/// <summary>
		/// Aborts all running threads except the current thread.
		/// </summary>
		public static void AbortThreads()
		{
			lock (Instance.SyncRoot)
			{
				foreach (WorkerThread wt in Instance.RegisteredWorkers.Values)
					wt.Abort(false);
			}
		}
	}
}
